package com.irdstudio.biz.drools.common;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Stack;

public class MapHelper {


    /**
     * 用于获取泛型获取类型
     */
    private static final List<Map> EMPTY_MAP_LIST = new ArrayList<Map>(1);

    /**
     * 操作枚举
     */
    private enum Operate {

        /**
         * 读操作
         */
        Read,
        /**
         * 写操作
         */
        Write
    }

    /**
     * 路径分隔符
     */
    public static final String PATH_SPLIT = ".";

    /**
     * 传入节点在树中的路径。
     *
     * @param path  路径
     * @param clazz 返回的值的类型
     * @param <T>   返回值的类型
     * @return 返回对应的值，如果为空，返回传入的默认值
     */
    public static <T> T getProperty(Map root, String path, Class<T> clazz) {
        Object obj = getValue(root, path);
        List<Object> objList = (List<Object>) obj;
        if (objList == null || objList.isEmpty() || objList.get(0) == null) {
            return null;
        }
        if (String.class == clazz && objList.get(0).getClass() != String.class) {
            String strVal = String.valueOf(objList.get(0)) ;
            return clazz.cast(strVal);
        }
        if (BigDecimal.class == clazz && objList.get(0).getClass() != BigDecimal.class) {
            BigDecimal strVal = new BigDecimal(objList.get(0).toString()) ;
            return clazz.cast(strVal);
        }
        T t = clazz.cast(objList.get(0));
        return t;
    }

    public static <T> T getProperty(Object root, String path, Class<T> clazz) {
        if (root instanceof Map) {
            return getProperty((Map)root, path, clazz);
        } else {
            return null;
        }
    }

    public static String getString(Object root, String path) {
        if (root instanceof Map) {
            return getProperty((Map)root, path, String.class);
        } else {
            return null;
        }
    }

    /**
     * 获取节点的数组。
     *
     * @param path  节点所在路径
     * @param array 数组的类型
     * @param <T>   返回值的类型
     * @return 返回对应路径的数组
     */
    private static <T> List<T> getPropertyList(Map root, String path, List<T> array) {
        Object obj = getValue(root, path);
        List<Object> objList = (List<Object>) obj;
        if (CollectionUtils.isEmpty(objList)){
            return Collections.EMPTY_LIST;
        }
        List<T> tList = new ArrayList<>(objList.size());
        for (Object o : objList) {
            T t = (T) o;
            tList.add(t);
        }
        return tList;
    }

    public static List<Map> getMapList(Map root, String path) {
        return getPropertyList(root, path, EMPTY_MAP_LIST);
    }

    public static List<Map> getMapList(Object root, String path) {
        if (root instanceof Map) {
            return getMapList((Map)root, path);
        } else {
            return null;
        }
    }

    /**
     * 将对应路径的节点的值设置为传入值
     *
     * @param path 节点所在路径
     * @param val  值
     * @param <T>  值的类型
     */
    public static <T> void setProperty(Map root, String path, T val) {
        setValue(root, path, val);
    }

    /**
     * 根据路径对bs取值
     *
     * @param path  路径
     * @return val
     */
    public static Object getValue(Map root, String path) {
        if (StringUtils.isBlank(path)) {
            return null;
        }
        Object obj = access(root, path, Operate.Read, null);
        return obj;
    }

    public static Object getValue(Object root, String path) {
        if (root instanceof Map) {
            return getValue((Map) root, path);
        } else {
            return null;
        }
    }

    /**
     * 塞值
     *
     * @param path 路径
     * @param val  设置的值
     */
    public static void setValue(Map root, String path, Object val) {
        if (StringUtils.isBlank(path)) {
            return;
        }
        access(root, path, Operate.Write, val);
    }

    /**
     * 迭代路径，根据枚举值做操作
     *
     * @param path    路径
     * @param operate 操作类型
     * @param val     值
     * @return 返回的值
     */
    private static Object access(Map root, String path, Operate operate, Object val) {
        Stack<String> stack = stackPath(path);
        Stack<Node<Map>> listStack = new Stack<>();
        Stack<String> backStack = new Stack<>();
        Stack<String> nextStack = new Stack<>();
        Map curRole = root;
        List<Object> result = new ArrayList<>();
        String curPath = stack.pop();
        while (true) {
            if (stack.isEmpty()) {
                //走到了叶子, 进行操作处理
                if (Operate.Read == operate) {
                    Object obj = curRole.get(curPath);
                    result.add(obj);
                } else if (Operate.Write == operate) {
                    curRole.put(curPath, val);
                }
                if (listStack.isEmpty()) {
                    //走完了所有的路
                    break;
                } else if (listStack.peek().hasNext()) {
                    curRole = listStack.peek().next();
                } else {
                    //退回去
                    listStack.pop();
                    if (listStack.isEmpty()) {
                        //无路可退
                        break;
                    }
                    //已经遍历完该节点，从栈顶移除
                    if (listStack.peek().hasNext()) {
                        curRole = listStack.peek().next();
                        //退回到上一层
                        stack.push(curPath);
                        curPath = backStack.pop();
                    } else {
                        // 上一层也已遍历结束
                        break;
                    }
                }
            } else {
                //还在途中
                Object child = curRole.get(curPath);
                if (child == null) {
                    return null;
                } else if (child instanceof List) {
                    List childList = (List) child;
                    if (childList.isEmpty()) {
                        return null;
                    }
                    Node<Map> childNode = new Node<>(childList, 1);
                    //列表中还有元素，推到栈顶中
                    listStack.push(childNode);
                    backStack.push(curPath);
                    //设置下一步节点
                    curRole = (Map) childList.get(0);
                    curPath = stack.pop();
                } else if (child instanceof Map) {
                    //设置下一步节点
                    curRole = (Map) child;
                    curPath = stack.pop();
                }
            }
        }

        return result;
    }

    /**
     * 返回路径的栈 eg : a.b.c = [a,b,c]
     *
     * @param path 路径
     * @return stack 栈
     */
    private static Stack<String> stackPath(String path) {
        String[] splitPath = path.split("\\.");
        Stack<String> stack = new Stack<>();
        for (int i = splitPath.length - 1; i >= 0; i--) {
            if (StringUtils.isNotBlank(splitPath[i])) {
                stack.push(splitPath[i]);
            } else {
                continue;
            }
        }
        return stack;
    }


    /**
     * 用于非递归遍历的栈节点封装
     *
     * @param <T> 节点的类型
     */
    static class Node<T> {
        /**
         * 节点列表
         */
        private List<T> list;

        /**
         * 列表的下一个下标
         */
        private int next;

        /**
         * 构造器
         *
         * @param list 节点列表
         * @param next 列表的下一个下标
         */
        public Node(List<T> list, int next) {
            this.list = list;
            this.next = next;
        }

        /**
         * 返回list下一个元素
         *
         * @return t
         */
        public T next() {
            if (hasNext()) {
                return this.list.get(next++);
            } else {
                return null;
            }
        }

        /**
         * hasNext
         *
         * @return true表示list还有可取的元素
         */
        public boolean hasNext() {
            return this.next >= 0 && this.next < this.list.size();
        }

        /**
         * 重写toString
         *
         * @return 对象包含的节点字符串
         */
        @Override
        public String toString() {
            return this.list.get(0).toString();
        }
    }
}
